package com.caishi.lkx.exam.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.caishi.lkx.exam.QuestionCollection;
import com.caishi.lkx.exam.QuestionCollectionBlockItem;
import com.caishi.lkx.exam.ienum.type.QuestionType;

import com.caishi.lkx.exam.model.QuestionModel;
import com.caishi.lkx.exam.records.dto.CollectionErrorAndCollectRecordDataDto;
import com.caishi.lkx.exam.records.dto.QuestionRecordsDto;

import com.caishi.lkx.exam.service.IQuestionService;
import com.caishi.lkx.exam.util.QuestionUtil;

import com.caishi.lkx.exam.vo.QuestionCollectStructureVo;
import com.caishi.lkx.exam.vo.QuestionCollectVo;
import com.caishi.lkx.exam.vo.QuestionStructureVo;
import com.caishi.lkx.exam.vo.QuestionVo;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.*;
import java.util.function.Consumer;
import java.util.stream.Collectors;

@Service
public class CoreQuestionCollectionService {

    @Resource
    private IQuestionService questionService;

    protected final Comparator<Integer> sortComparator = (o1, o2) -> {
        if (o1 == null && o2 == null) {
            return 0;
        }
        if (o1 == null) return -1;
        if (o2 == null) return 1;
        return o1.compareTo(o2);
    };


    public final QuestionCollectVo clientCollectionData(QuestionCollection<?, ?> model, String industryId, String examId, Long categoryId) {
        List<String> ids = model.getContent().stream().flatMap(v -> v.getQs().stream().map(QuestionCollectionBlockItem.QuestionCollectionItem::getId)).toList();

        var questionData = ids.isEmpty() ? Collections.<QuestionVo>emptyList() :
                questionService.clientQuestionCollection(ids, industryId, examId, categoryId);
        return clientCollectionData(model, questionData, industryId, examId, categoryId);
    }

    public final QuestionCollectVo clientCollectionData(QuestionCollection<?, ?> model, List<QuestionVo> questionVos, String industryId, String examId, Long categoryId) {
        var result = new QuestionCollectVo();
        var questionData = questionVos.stream().collect(Collectors.toMap(QuestionVo::getId, v -> v, (existingValue, newValue) -> existingValue));
        result.setName(model.getName());
        result.setId(model.getId());
        result.setContent(model.getContent().stream().map(item -> {
            var itemVo = new QuestionCollectVo.QuestionCollectionBlockItemVo(item);
            itemVo.setQs(item.getQs().stream().map(v -> {
                var vo = new QuestionCollectVo.QuestionCollectionBlockItemVo.QuestionCollectionItemVo(v);
                var qd = questionData.get(v.getId());
                if (qd == null) {
                    return null;
                }
                BeanUtil.copyProperties(qd, vo);
                return vo;
            }).filter(Objects::nonNull).sorted((v, v1) -> sortComparator.compare(v.getSort(), v1.getSort())).toList());
            if (CollUtil.isEmpty(itemVo.getQs())) return null;
            return itemVo;
        }).filter(Objects::nonNull).sorted((v, v1) -> sortComparator.compare(v.getSort(), v1.getSort())).toList());
        return result;
    }

    public final QuestionCollectStructureVo collectionDataStructure(QuestionCollection<?, ?> model, String industryId, String examId, Long categoryId) {
        var result = new QuestionCollectStructureVo();
        List<String> ids = model.getContent().stream().flatMap(v -> v.getQs().stream().map(QuestionCollectionBlockItem.QuestionCollectionItem::getId)).toList();
        var questionData = ids.isEmpty() ? new HashMap<String, QuestionStructureVo>() : questionService.questionCollectionStructure(ids, industryId, examId, categoryId).stream().collect(Collectors.toMap(QuestionStructureVo::getId, v -> v));
        result.setName(model.getName());
        result.setId(model.getId());
        result.setContent(model.getContent().stream().map(item -> {
            var itemVo = new QuestionCollectStructureVo.QuestionCollectionBlockItemVo(item);
            itemVo.setQs(item.getQs().stream().map(v -> {
                var vo = new QuestionCollectStructureVo.QuestionCollectionBlockItemVo.QuestionCollectionItemVo(v);
                var qd = questionData.get(v.getId());
                if (qd == null) {
                    return null;
                }
                BeanUtil.copyProperties(qd, vo);
                if (vo.getFirstType().equals(QuestionType.combination)) {
                    List<QuestionModel> combineList = questionService.getCombineList(vo.getId());
                    List<QuestionStructureVo> childs = new ArrayList<>();
                    combineList.forEach(q -> {
                        var itemVo1 = new QuestionCollectStructureVo.QuestionCollectionBlockItemVo.QuestionCollectionItemVo();
                        itemVo1.setFirstType(q.getFirstType());
                        itemVo1.setSort(q.getSort());
                        itemVo1.setScore(q.getScore());
                        itemVo1.setId(q.getId());
                        itemVo1.setType(questionService.questionTypeName(q.getTypeId(), q.getFirstType()));
                        childs.add(itemVo1);
                    });
                    vo.setChildren(childs);
                }
                return vo;
            }).filter(Objects::nonNull).sorted((v, v1) -> sortComparator.compare(v.getSort(), v1.getSort())).toList());
            if (CollUtil.isEmpty(itemVo.getQs())) return null;
            return itemVo;
        }).filter(Objects::nonNull).sorted((v, v1) -> sortComparator.compare(v.getSort(), v1.getSort())).toList());
        return result;
    }

    public final QuestionCollectVo safeProcess(QuestionRecordsDto record, CollectionErrorAndCollectRecordDataDto collectChapterDataDto, QuestionCollectVo result, String targetId, Serializable collectId, boolean setRightAnswer) {
        return safeProcess(record, collectChapterDataDto, result, targetId, collectId, setRightAnswer, false);
    }

    public final QuestionCollectVo safeProcess(QuestionRecordsDto record, CollectionErrorAndCollectRecordDataDto collectChapterDataDto,
                                               QuestionCollectVo result, String targetId, Serializable collectId, boolean setRightAnswer, boolean forceRightAnswer) {
        result.setLastId(record.getData().getString(QuestionRecordsDto.LAST_ID));
        return collectVoForEach(result, q -> {
            var r = record.get(q.getId());
            if (!forceRightAnswer && targetId != null) {
                if (!setRightAnswer || r == null) {
                    q.setAnswerBase64(questionService.answerEncrypt(q.getRightAnswer(), targetId, collectId.toString()));
                    q.setRightAnswer(null);
                }
            }
            if (r != null) {
                q.setRecord(r);
            }
            q.setCollect(collectChapterDataDto.getData().containsKey(q.getId()));
        });
    }


    public final QuestionCollectVo collectVoForEach(QuestionCollectVo result, Consumer<QuestionVo> voConsumer) {
        for (var v : result.getContent()) {
            for (var v1 : v.getQs()) {
                if (QuestionUtil.questionIdIsCombinationParent(v1.getId())) {
                    voConsumer.accept(v1);
                    if (v1.getChildren() != null) {
                        for (var v2 : v1.getChildren()) {
                            voConsumer.accept(v2);
                            v2.setCid(v1.getCid());
                            v2.setCn(v1.getCn());
                        }
                    }
                } else {
                    voConsumer.accept(v1);
                }
            }
        }
        return result;
    }

}
